﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using Mesuro.Common;
using System.Windows;
using Vector = Mesuro.Common.Vector;
using System.Windows.Media;
using Mesuro.Graphing.Utilities;
using System.Windows.Data;
using System.Windows.Media.Effects;
using System.Windows.Shapes;

namespace Mesuro.Graphing.Plots {
	public static class Plots2D {

		#region DP: PlotMarker
		public static readonly DependencyProperty PlotMarkerProperty = DependencyProperty.RegisterAttached( "PlotMarker", typeof( Geometry ), typeof( Plots2D ), new FrameworkPropertyMetadata( PlotMarkers.Circle, FrameworkPropertyMetadataOptions.None, PlotMarkerChangedStatic ) );
		public static Geometry GetPlotMarker( DependencyObject element ) { return (Geometry)element.GetValue( PlotMarkerProperty ); }
		public static void SetPlotMarker( DependencyObject element, Geometry value ) { element.SetValue( PlotMarkerProperty, value ); }
		private static void PlotMarkerChangedStatic( DependencyObject sender, DependencyPropertyChangedEventArgs e ) { }
		#endregion

		#region DP: MarkerSize
		public static readonly DependencyProperty MarkerSizeProperty = DependencyProperty.RegisterAttached( "MarkerSize", typeof( MarkerSize ), typeof( Plots2D ), new FrameworkPropertyMetadata( MarkerSize.Medium, FrameworkPropertyMetadataOptions.None, MarkerSizeChangedStatic ) );
		public static MarkerSize GetMarkerSize( DependencyObject element ) { return (MarkerSize)element.GetValue( MarkerSizeProperty ); }
		public static void SetMarkerSize( DependencyObject element, MarkerSize value ) { element.SetValue( MarkerSizeProperty, value ); }
		private static void MarkerSizeChangedStatic( DependencyObject sender, DependencyPropertyChangedEventArgs e ) { }
		#endregion

		static Plots2D() {
			GraphingRegistry.RegisterRenderer( PLOT_LinePlot, typeof( LinePlotRendererContent ), new Type[] { typeof( Plot ) }, new object[] { null } );
		}
		public static void Load() {
			//NOP
			//This function provides a way to force the static initialiser to be called
		}

		public const string PLOT_LinePlot = "Line Plot";
		private class LinePlotRendererContent : FrameworkElement, IPlotContent {
			private Plot plot;

			private Path path = new Path() { StrokeThickness = 1, Stretch = Stretch.Fill };

			public LinePlotRendererContent( Plot plot ) {
				this.plot = plot;

				path.SetBinding( Path.StrokeProperty, new Binding() { Path = new PropertyPath( Plot.BrushProperty ), Source = plot } );

				path.Measure( new Size( 0, 0 ) );

				AddVisualChild( path );
			}

			public void Update() {
				PathGeometry pg = new PathGeometry();
				pg.Figures = new PathFigureCollection( 1 );
				PolyLineSegment pl = new PolyLineSegment( plot.PlotData.Select( ( x ) => ((Point)x.Top( 2 )) ), true );

				if (pl.Points.Count < 1) {
					path.Visibility = Visibility.Collapsed;
					return;
				} else
					path.Visibility = Visibility.Visible;

				Point start = pl.Points[0];
				pl.Points.RemoveAt( 0 );
				pg.Figures.Add( new PathFigure( start, new PathSegment[] { pl }, false ) );
				path.Data = pg;
			}

			protected override Size ArrangeOverride( Size finalSize ) {
				path.Arrange( new Rect( finalSize ) );

				return base.ArrangeOverride( finalSize );
			}

			protected override Visual GetVisualChild( int index ) {
				return path;
			}

			protected override int VisualChildrenCount {
				get {
					return 1;
				}
			}
		}
	}
}
